swadhinbiswas feat: finalize platform polish - discussions, gists, webhook queue, realtime, push-mirror, auth/metrics hardening · 8/28/2026
f02976d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* Single Gist API
* GET /api/gists/[id] — fetch gist (owner or public/secret visibility)
* PATCH /api/gists/[id] — owner only; wholesale replace description/files/public
* DELETE /api/gists/[id] — owner only
*/
import { getDatabase, schema } from "@/db";
import { gists } from "@/db/schema/gists";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import { badRequest, noContent, notFound, forbidden, success, unauthorized } from "@/lib/api";
import { getUserFromRequest } from "@/lib/auth";
import { withErrorHandler } from "@/lib/errors";
import { logger } from "@/lib/logger";
import type { APIRoute } from "astro";
import { eq } from "drizzle-orm";
import { z } from "zod";
import { createGistSchema, gistFilesSchema } from "../index";
export const updateGistSchema = z.object({
description: z.string().max(500).optional(),
public: z.boolean().optional(),
files: gistFilesSchema.optional(),
});
async function findGist(db: NodePgDatabase<typeof schema>, id: string) {
return db.query.gists.findFirst({
where: eq(gists.id, id),
});
}
export const GET: APIRoute = withErrorHandler(async ({ request, params }) => {
const tokenPayload = await getUserFromRequest(request);
const db = getDatabase() as unknown as NodePgDatabase<typeof schema>;
const gist = await findGist(db, params.id!);
if (!gist) return notFound("Gist not found");
// Secret gists are only visible to their owner
if (!gist.public && gist.userId !== tokenPayload?.userId) {
return notFound("Gist not found");
}
return success({
...gist,
isOwner: gist.userId === tokenPayload?.userId,
});
});
export const PATCH: APIRoute = withErrorHandler(async ({ request, params }) => {
const tokenPayload = await getUserFromRequest(request);
if (!tokenPayload) {
return unauthorized("You must be logged in to edit a gist");
}
let raw: unknown;
try {
raw = await request.json();
} catch {
return badRequest("Invalid JSON body");
}
const result = updateGistSchema.safeParse(raw);
if (!result.success) {
return badRequest("Invalid input", result.error.flatten());
}
const db = getDatabase() as unknown as NodePgDatabase<typeof schema>;
const gist = await findGist(db, params.id!);
if (!gist) return notFound("Gist not found");
if (gist.userId !== tokenPayload.userId) {
return forbidden("You do not have permission to edit this gist");
}
const updates: Partial<typeof gists.$inferInsert> = { updatedAt: new Date() };
if (result.data.description !== undefined) {
updates.description = result.data.description;
}
if (result.data.public !== undefined) {
updates.public = result.data.public;
}
if (result.data.files !== undefined) {
updates.files = result.data.files;
}
await db.update(gists).set(updates).where(eq(gists.id, gist.id));
logger.info({ userId: tokenPayload.userId, gistId: gist.id }, "Gist updated");
return success({ ...gist, ...updates });
});
export const DELETE: APIRoute = withErrorHandler(async ({ request, params }) => {
const tokenPayload = await getUserFromRequest(request);
if (!tokenPayload) {
return unauthorized("You must be logged in to delete a gist");
}
const db = getDatabase() as unknown as NodePgDatabase<typeof schema>;
const gist = await findGist(db, params.id!);
if (!gist) return notFound("Gist not found");
if (gist.userId !== tokenPayload.userId) {
return forbidden("You do not have permission to delete this gist");
}
await db.delete(gists).where(eq(gists.id, gist.id));
logger.info({ userId: tokenPayload.userId, gistId: gist.id }, "Gist deleted");
return noContent();
});